#pragma once

#include "TableUser.h"
#include "QuotaMap.h"
namespace qb{
	namespace ht{
		class TableUser;
		class TableCache;
		class ITableCache;
		enum kTableProperty{
			kTablePropertyNone,
			kTablePropertyMemory,
			kTablePropertyFileSize,
			kTablePropertyFileViewSize,
			kTablePropertyFilePageSize,
			kTablePropertyCacheSwapCount,
			kTablePropertyCacheWriteCount,
			kTablePropertyRecordSize,
			kTablePropertyKeySize,
			kTablePropertyQuotaCapcity,
			kTablePropertyQuotaLength,
			kTablePropertyMax
		};
		enum kRecordChannel{
			kRecordChannelDefault = 0,			// 默认
			kRecordChannelCompareFirst,		// 对比两条记录的时候,读取前一条记录
			kRecordChannelCompareLast,		// 对比两条记录的时候,读取后一条记录
			kRecordChannelOldData,			//写入记录的时候保持该记录的上一个状态的值
			kRecordChannelDirect,
			kRecordChannelCount
		};
        class RecordResult{
			struct RecordLine{
				int		rid;
				int		index;
				int		size;
				char*	buf;
				RecordLine(int s) :rid(-1), index(-1),size(s){ buf = new char[size]; memset(buf, 0, size); }
				~RecordLine(){ if (buf) delete[] buf; buf = 0; }
				void Reset(int r,int i){ rid = r, index = i, memset(buf, 0, size); }
				static int CompareRID(const void* p1, const void* p2)
				{
					const RecordLine* r1 = *((const RecordLine**)p1);
					const RecordLine* r2 = *((const RecordLine**)p2);
					return r1->rid-r2->rid;
				}
				static int CompareIndex(const void* p1, const void* p2)
				{
					const RecordLine* r1 = *((const RecordLine**)p1);
					const RecordLine* r2 = *((const RecordLine**)p2);
					return r1->index - r2->index;
				}
			};
            std::vector<RecordLine*>				m_records;
			int								m_count;
			int								m_record_size;
			int								m_buf_size;
		public:
			RecordResult(int recordSize) :m_record_size(recordSize), m_buf_size(recordSize + 4), m_count(0){}
			~RecordResult(){
				for (int i = 0; i < (int)m_records.size();i++)
				{
					delete m_records[i];
				}
				m_records.clear();
			}
            void SetKeys(const std::vector<TableUser::RecordKey>& keys)
			{
				while (m_records.size()<keys.size())
				{
					m_records.push_back(new RecordLine(m_buf_size));
				}
				for (int i = 0; i < (int)keys.size();i++)
				{
					m_records[i]->Reset(keys[i].rid, i);
				}
				m_count = keys.size();
				qsort(&m_records.at(0), m_count, sizeof(RecordLine*), RecordLine::CompareRID);
			}
			int GetCount()const{ return m_count; }
			int  GetRecordId(int index)
			{
				return m_records[index]->rid;
			}
			void SetRecord(int index, const char* record)
			{
				memcpy(m_records[index]->buf, record, m_record_size);
				m_records[index]->buf[m_record_size] = 0;
			}

			void SortByIndex()
			{
				qsort(&m_records.at(0), m_count, sizeof(RecordLine*), RecordLine::CompareRID);
			}
			const char* GetRecord(int index)
			{
				return m_records[index]->buf;
			}
		};
        class Table{
			struct Record{					// 用于暂存一条记录的对象
				char*	m_buf;				// 固定长度的缓存
				int		m_size;				// 固定长度
				int		m_rid;				// 记录id
			};
            typedef std::map<void*, TableUser*> TableUserMap;
            typedef std::map<std::string, int>	ColumnNameMap;
			class WriteListener : public QuotaMap::Listener{
				Table*		m_table;
			public:
				WriteListener(Table* table) :m_table(table){}
				virtual void OnWrite(int rid, const void* prev, const void* cur, int size, bool insert);
			};
			ITableCache*			m_cache;			//
			TableUserMap			m_users;			//
			FastLock				m_lock;				//
			TableDesc				m_desc;				//
			int						m_tableid;			// 内部标识，替换m_name，用以提升性能
			int						m_head_size;
			int						m_viewsize, m_increase_size;
			std::string				m_name;				// 仅作调试查看用
            std::string				m_cache_filename;
            std::string				m_tagname;
			WriteListener*			m_write_listener;	// 
			BoolVec					m_field_changed;		// 每次写一条记录的时候，会更新此数据
			Record					m_records[kRecordChannelCount];
			bool					m_field_change_notify;
			bool					m_flag_useldb;
			ColumnNameMap			m_column_name_map;
		public:
			Table(const TableDesc& desc, int tableid, int headSize, bool use_ldb = false);
			~Table();
			void SetCacheCapcity(int capcity);
			void SetViewSize(int view){ m_viewsize = view; }
			void SetIncreaseSize(int increase){ m_increase_size = increase; }
            bool Initialize(const std::string& fname = "", const std::string& tag = "", bool temp=false);

			void Unload();
			void Reload();

			// 添加用户
			void AddUser(TableUser* user);
			int GetUserCount()const{ return m_users.size(); }
            TableUser* GetUser(void* wnd);
			TableUser* GetUser(int index);

			// 信息获取
			int GetRecordLength()const;
			void SetName(const char* name){ m_name = name ? name : ""; }
			const std::string& GetName()const{ return m_name; }
			int GetTableId()const{ return m_tableid; }
			int GetColumnCount()const{ return m_desc.GetColumns().size(); }
			const ColumnInfo& GetColumnInfo(int index)const{ return m_desc.GetColumns().at(index); }

			// 读取记录
			void ReadRecords(RecordResult& rr);
			const char* ReadRecord(int rid, kRecordChannel channel = kRecordChannelDefault);
			const char* GetRecordOldData()const{ return m_records[kRecordChannelOldData].m_buf; }
			
			const char* ReadRecordDirect(int rid);
			void WriteRecordDirect(int rid, const void* record, int size);
			RecordId WriteRecordDirect(const void* record, int size);

            void ReadColumns(int rid, const std::vector<kColumn>& columns, char*buf, int size);

			void SortForUser(int index);

			RecordId RemoveRecord(const void* key);
			RecordId WriteRecord(const void* record, int size);
            void WriteRecordFields(const void* record, int size,int rid,const std::vector<bool>& fields);
			ITableCache* GetCache();

			int GetRemapCount()const;
			int GetMaxRecordId()const;
			//void GetKeyColumn(const void* record, int size,RecordKey& key);
			ViewInfo GetViewInfo();
			const char* GetKeyColumn(const void* record, int size);

			kColumn GetKeyColumn();
			kColumn GetColumnByName(const char* name);
			int GetRecordCount()const;

			RecordId GetRecordIdByKey(const void* key);

			int GetProperty(kTableProperty tp);
			std::string GetCacheFileName();

			static kTableProperty GetPropertyByName(const char* name);
			static const char*    GetPropertyName(kTableProperty tp);
		public:
			void DumpStatus(int mode = 0);
		protected:
			char* ReadRecordInternal(int rid, kRecordChannel channel = kRecordChannelDefault);
			void UpdateFieldChangedFlags(int rid, const void* prev, const void* cur, int size, bool insert);
		};
	}//namespace ht
}//namespace qb

